﻿using System;
using System.Linq;
using System.Linq.Expressions;

namespace PNAB.DAL
{
    /// <summary>
    /// Generic repository is used to provide a set of CRUD operations, to perform on the database,
    /// using the given database entity as the predicate.
    /// 
    /// All methods of the repository should throw an exception, in case if underlying database
    /// will fail to respond.
    /// </summary>
    /// <typeparam name="TEntity">The database entity model, on which we want to operate.</typeparam>
    public interface IGenericRepository<TEntity> : IDisposable where TEntity : class
    {
        /// <summary>
        /// Method used to get the list of entities from the database,
        /// given certain preconditions.
        /// Method should return an empty list in case if no entities fulfill
        /// the precondition.
        /// </summary>
        /// <param name="precondition">The precondition specific to the given entity. Can be 
        /// null, in that case all entities should be returned.</param>
        /// <param name="orderBy">The ordering precondition, which defines how the returned 
        /// list should be sorted. Can be null, in that case entities
        /// should be returned in the order, they were obtained from the database.</param>
        /// <param name="includeProperties">The comma separated string, containing the names
        /// of the entity properties, which should be includded into the returning objects.
        /// Can be empty, in that case the returning entities should have those properties,
        /// which are by default returned from the database.</param>
        /// <returns>The list of entities that fulfill the given precondition.</returns>
        IQueryable<TEntity> Get(
            Expression<Func<TEntity, bool>> precondition = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "");

        /// <summary>
        /// Method used to get an entity from the database, based on it's primary key.
        /// Method should return null if no such object has been found.
        /// </summary>
        /// <param name="id">The primary key value for which the query should look for.</param>
        /// <returns>The database entity with the provided primary key value.</returns>
        TEntity GetById(object id);

        /// <summary>
        /// Method used to get an entity from the database, based on the defined precondition.
        /// Method should return null if no such object has been found.
        /// Method should throw an exception if more than one element fulfill the precondition.
        /// </summary>
        /// <param name="precondition">The precondition specific to the given entity. In case of 
        /// null precondition, a null value should be returned.</param>
        /// <returns>The database entity which fulfills the given precondition.</returns>
        TEntity GetSingle(
            Expression<Func<TEntity, bool>> precondition = null);

        /// <summary>
        /// Method used to insert a given entity into the database.
        /// </summary>
        /// <param name="entity">An entity which should be added into the database.</param>
        void Insert(TEntity entity);

        /// <summary>
        /// Method used to update a given entity in the database.
        /// </summary>
        /// <param name="entity">An entity which should be updated.</param>
        void Update(TEntity entity);

        /// <summary>
        /// Method used to delete an entity from the database based on the given primary key value.
        /// Method should throw an exception if given entity won't we found.
        /// </summary>
        /// <param name="id">The value of the primary key of the entity to be deleted.</param>
        void Delete(object id);

        /// <summary>
        /// Method used to delete an entity from the database based on the given primary key value.
        /// </summary>
        /// <param name="entity">The representation of the entity to be deleted.</param>
        void Delete(TEntity entity);
    }
}
